﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Models
{
	public class AwaitLock : IDisposable
	{
		private static SemaphoreSlim _global = new SemaphoreSlim(1);
		private SemaphoreSlim _semaphore;
		private Action _onDispose;

		private AwaitLock(bool isGlobal)
		{
			if (isGlobal)
			{
				_semaphore = _global;
			}
			else
			{
				_semaphore = new SemaphoreSlim(1);
			}
		}

		public void Dispose()
		{
			if (_onDispose != null)
			{
				_onDispose();
				_onDispose = null;
			}

			_semaphore.Release();
		}

		public async Task<AwaitLock> Lock()
		{
			await _semaphore.WaitAsync();
			return this;
		}

		public async Task<AwaitLock> Lock(CancellationToken cancellationToken)
		{
			await _semaphore.WaitAsync(cancellationToken);
			return this;
		}

		public async Task<AwaitLock> Lock(Action onDispose)
		{
			await _semaphore.WaitAsync();
			_onDispose = onDispose;
			return this;
		}

		public static AwaitLock CreateIndividual()
		{
			return new AwaitLock(isGlobal: false);
		}

		public static AwaitLock CreateGlobal()
		{
			return new AwaitLock(isGlobal: true);
		}
	}
}
